#include "project.h"
#include <QDir>
#include <QFile>
#include <QXmlStreamWriter>
#include <QDebug>
#include <QMessageBox>
#include <QProgressDialog>
#include <QCoreApplication>

#include "designerworkbench.h"
#include "designer_formwindow.h"
#include "defines.h"

#include <QtDesigner/QDesignerFormWindowManagerInterface>
#include <QtDesigner/QDesignerFormEditorPluginInterface>

#include "abstractcontainer.h"

Project::Project(const QString &fileName):m_workbench(QDesignerWorkbench::instance())
{    
    m_projectFile = fileName;
    m_projectVersion = "1";

    int p1 = fileName.lastIndexOf('/');
    if(p1<0) p1 = 0;

    int p2 = fileName.lastIndexOf('.');
    if(p2<0)
    {
        p2 = fileName.size();
        m_projectFile+=".sp";
    }
    m_projectName = fileName.mid(p1+1,p2-p1-1);
    m_projectPath = fileName.left(p1);
    m_scriptFilename = "projectScript.js";
    m_projectScript = "function main()\n{\n}";
    m_databases = new AbstractContainer( XML_DATABASES );
}

Project::~Project()
{
    delete m_databases;
}

bool Project::isValid()
{
    return !m_projectName.isEmpty();
}

QString Project::fileFullName() const
{

    return m_projectFile;
}

bool Project::write()
{
    bool res = true;
    if(isValid())
    {
        QFile file(m_projectFile);
        res = file.open(QFile::WriteOnly);
        if(!res) return res;
        QXmlStreamWriter stream(&file);
        stream.setAutoFormatting(true);
        stream.writeStartDocument();

        stream.writeStartElement(XML_PROJECT);
        stream.writeAttribute(XML_PROJECTNAME, m_projectName);
        stream.writeAttribute(XML_VERSION, m_projectVersion);
        stream.writeAttribute(XML_PROJECTSCRIPT, m_scriptFilename);


        // ******************** Forms info ****************************
        stream.writeStartElement(XML_FORMSLIST);
        for(int i = 0; i < m_workbench->formWindowCount() && res; i++)
        {
            QDesignerFormWindow *fw =  m_workbench->formWindow(i);

            stream.writeStartElement(XML_FORM);
            stream.writeAttribute("id", QString::number(i));
            QDesignerFormWindowInterface *wnd = fw->editor();
            QDir dir(m_projectPath);            
            stream.writeAttribute(XML_FORMFILE,dir.relativeFilePath(wnd->fileName())); // Form file
            QString scrFile = dir.relativeFilePath(wnd->fileName());
            scrFile.replace(scrFile.length()-3,3,".js");
            QFile txtFile(dir.absoluteFilePath(scrFile));
            res = txtFile.open(QFile::WriteOnly|QFile::Text);
            txtFile.write(fw->script().toUtf8());
            txtFile.close();
            stream.writeAttribute(XML_SCRIPTFILE, scrFile);   // Script file

            QList<QDesignerFormWindow::Connection>* conns =  fw->connections();
            if(conns->size()>0)
            {
                stream.writeStartElement(XML_CONNECTIONS);

                for(int i = 0; i<conns->size(); i++)
                {
                    stream.writeStartElement(XML_CONNECTION);
                    stream.writeAttribute(XML_SENDER, conns->at(i).sender);
                    stream.writeAttribute(XML_SIGNAL, conns->at(i).signal);
                    stream.writeAttribute(XML_RECEIVER, conns->at(i).receiver);
                    stream.writeAttribute(XML_SLOT, conns->at(i).slot);
                    stream.writeEndElement(); // connection
                }

                stream.writeEndElement(); // connections
            }
            stream.writeEndElement(); // form
        }
        stream.writeEndElement(); // forms
        // ************************************************************

        m_databases->writeToXml(&stream);

        stream.writeEndElement(); // project

        stream.writeEndDocument();
        file.close();
        saveScript();
        res = true;
    }
    else
    {
        qDebug()<<"error project write:"<<fileFullName();
    }
    return res;
}

bool Project::read()
{
    bool res = true;
    QXmlStreamReader xml;
    QFile file(m_projectFile);
    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        QMessageBox::critical((QWidget*)m_workbench->mainWindow(), "Error",
                             QObject::tr("Cannot read file %1:\n%2.")
                             .arg(m_projectFile)
                             .arg(file.errorString()),QMessageBox::Close);
        return false;
    }

    xml.setDevice(&file);
    QProgressDialog progress(QString(),0,0,file.size(),(QWidget*)m_workbench->mainWindow(),Qt::ToolTip);
    progress.setWindowTitle(QObject::tr("Loading"));
    progress.show();

    while(!xml.atEnd() && res)
    {
        xml.readNext();
        if(xml.isStartElement())
        {
            if(xml.name() == XML_PROJECT)
            {
                QXmlStreamAttributes atribs = xml.attributes();
                m_projectName = atribs.value(XML_PROJECTNAME).toString();
                m_projectVersion = atribs.value(XML_VERSION).toString();
                m_scriptFilename = atribs.value(XML_PROJECTSCRIPT).toString();
            }
            else if(xml.name() == XML_FORMSLIST)
            {
                xml.readNext();
                while( !(xml.name() == XML_FORMSLIST) )
                {
                    if(xml.name() == XML_FORM && xml.isStartElement())
                    {
                        res = readForms(&xml,&progress);
//                        QString errorMessage;
//                        res = m_workbench->openForm(formFile, &errorMessage)!=0;
                    }
                    xml.readNext();
                }
            }
            else if(xml.name() == XML_DATABASES)
            {
                m_databases->readFromXml(&xml);
            }
            QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
            progress.setValue(xml.characterOffset());
        }
    }
    loadScript();
    if(res) res = !xml.hasError();

    return res;
}


bool Project::readForms(QXmlStreamReader *xml, QProgressDialog *progress)
{
    bool res = true;
    QString errorMessage;
    QDesignerFormWindow *form = 0;
    QDir dir(m_projectPath);
    while(res && !xml->atEnd() && !(xml->name()==XML_FORM && xml->isEndElement()) )
    {
        if(xml->name() == XML_FORM && xml->isStartElement())
        {
            QXmlStreamAttributes formAtribs = xml->attributes();
            QString formFile = dir.absoluteFilePath(formAtribs.value(XML_FORMFILE).toString());
            form = m_workbench->openForm(formFile, &errorMessage);
            res = form != 0; // is pointer not null

            QString scriptFile = dir.absoluteFilePath(formAtribs.value(XML_SCRIPTFILE).toString());
            if(form)
            {
                QFile file(scriptFile);
                res = file.open(QFile::ReadOnly|QFile::Text);
                if(res)
                {
                    QByteArray scriptText;

                    while (!file.atEnd()) {
                        scriptText += file.readLine();
                    }

                    form->setScript(scriptText);
                }
                file.close();
            }
        }
        else if( xml->name() == XML_CONNECTIONS && form)
        {
            while( !(xml->name() == XML_CONNECTIONS && xml->isEndElement()) && !xml->atEnd() )
            {
                xml->readNext();
                if(xml->isStartElement() && xml->name() == XML_CONNECTION)
                {
                    QList<QDesignerFormWindow::Connection>* cons = form->connections();
                    QXmlStreamAttributes conAtribs = xml->attributes();
                    QDesignerFormWindow::Connection con;
                    con.sender = conAtribs.value(XML_SENDER).toString();
                    con.receiver = conAtribs.value(XML_RECEIVER).toString();;
                    con.signal = conAtribs.value(XML_SIGNAL).toString();;
                    con.slot = conAtribs.value(XML_SLOT).toString();;
                    cons->append(con);
                }
            }
        }

        xml->readNext();
        if(progress)
        {
            QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
            progress->setValue(xml->characterOffset());
        }
    }
    return res;
}

void Project::saveScript()
{
    QString fileName = m_projectPath + "/" + m_scriptFilename;
    QFile file(fileName);

    if( file.open(QFile::WriteOnly) )
    {
        file.write( m_projectScript.toUtf8() );
        file.close();
    }
}

void Project::loadScript()
{
    QString fileName = m_projectPath + "/" + m_scriptFilename;
    QFile file(fileName);

    if( file.open(QFile::ReadOnly|QFile::Text) )
    {
        QByteArray scriptText;
        while (!file.atEnd()) {
            scriptText += file.readLine();
        }
        setScript( scriptText );
    }
}
